﻿Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports forms = System.Windows.Forms
Imports draw = System.Drawing
Imports System.Windows.Interop
Imports System.Windows.Threading
Imports Send2Twitter
Imports Send2Twitter.Settings

Class MainWindow
    Implements INotifyPropertyChanged

    Private InfoG As InfoGen
    Private InfoP As InfoProccessors
    Private InfoS As InfoSenders

    Private MyHotKeyID As Integer
    Private BindedHotKey As Boolean = False
    Dim wnd As IntPtr

    Private WithEvents _sendTimer As DispatcherTimer = New DispatcherTimer(DispatcherPriority.Normal, Me.Dispatcher)

    Protected Friend WithEvents NfyIcon As forms.NotifyIcon

    Public ReadOnly Property SendTimer As DispatcherTimer
        Get
            Return _sendTimer
        End Get
    End Property

    Public Property Generator As InfoGen
        Get
            Return InfoG
        End Get
        Set(value As InfoGen)
            InfoG = value
            OnPropertyChanged("Generator")
        End Set
    End Property

    Public Property Proccessor As InfoProccessors
        Get
            Return InfoP
        End Get
        Set(value As InfoProccessors)
            InfoP = value
            OnPropertyChanged("Proccessor")
        End Set
    End Property

    Public Property Sender As InfoSenders
        Get
            Return InfoS
        End Get
        Set(value As InfoSenders)
            InfoS = value
            OnPropertyChanged("Sender")
        End Set
    End Property

    Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing
        _sendTimer.Stop()
        If My.Settings.IsWorking Then
            UnbindHotKey()
        End If
        On Error Resume Next
        Me.Generator.Dispose()
        Me.Proccessor.Dispose()
        Me.Sender.Dispose()
        NfyIcon.Dispose()
        NfyIcon = Nothing
        On Error GoTo 0
    End Sub

    Protected Overrides Sub OnSourceInitialized(e As System.EventArgs)
        MyBase.OnSourceInitialized(e)
        wnd = New WindowInteropHelper(Me).Handle
        Dim source As HwndSource = PresentationSource.FromVisual(Me)
        source.AddHook(AddressOf WndProc)
    End Sub

    Private Sub MainWindow_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
        Me.CommandBindings.Add(New CommandBinding(Commands.RefreshAddin, New ExecutedRoutedEventHandler(AddressOf RefreshAddin_Executed)))
        Me.CommandBindings.Add(New CommandBinding(Commands.AddPath, New ExecutedRoutedEventHandler(AddressOf AddPath_Executed)))
        Me.CommandBindings.Add(New CommandBinding(Commands.DeletePath, New ExecutedRoutedEventHandler(AddressOf DeletePath_Executed)))
        Me.CommandBindings.Add(New CommandBinding(Commands.Check, New ExecutedRoutedEventHandler(AddressOf Check_Exectued)))
        Me.CommandBindings.Add(New CommandBinding(Commands.ShowSetting, New ExecutedRoutedEventHandler(AddressOf ShowSetting_Exectued)))
        Me.CommandBindings.Add(New CommandBinding(Commands.StartWork, New ExecutedRoutedEventHandler(AddressOf StartWork_Exectued)))
        Me.CommandBindings.Add(New CommandBinding(Commands.ChangeHideState, New ExecutedRoutedEventHandler(AddressOf ChangeHideState_Exectued)))
        Me.Generator = New InfoGen(Settings.Settings.Default.InfoGens.SearchPath)
        Me.Proccessor = New InfoProccessors(Settings.Settings.Default.Proccessors.SearchPath)
        Me.Sender = New InfoSenders(Settings.Settings.Default.Senders.SearchPath)

        _sendTimer.Interval = TimeSpan.FromMinutes(My.Settings.TimerInterval)
        _sendTimer.IsEnabled = My.Settings.IsWorking And My.Settings.UseTimer
        AddHandler My.Settings.PropertyChanged, New PropertyChangedEventHandler(
            Sub(_sender As Object, _e As System.ComponentModel.PropertyChangedEventArgs)
                If _e.PropertyName = "IsWorking" Then
                    If My.Settings.IsWorking Then
                        Me.Dispatcher.Invoke(DispatcherPriority.Background, Sub() BindHotKey())
                    Else
                        Me.Dispatcher.Invoke(DispatcherPriority.Background, Sub() UnbindHotKey())
                    End If
                    Me.Dispatcher.Invoke(DispatcherPriority.Background, Sub() _sendTimer.IsEnabled = My.Settings.IsWorking AndAlso My.Settings.UseTimer)
                ElseIf _e.PropertyName = "UseTimer" Then
                    Me.Dispatcher.Invoke(DispatcherPriority.Background, Sub() _sendTimer.IsEnabled = My.Settings.IsWorking AndAlso My.Settings.UseTimer)
                End If
            End Sub)
        My.Settings.IsWorking = My.Settings.IsWorking
    End Sub

    Private Sub AddPath_Executed(sender As System.Object, e As System.Windows.Input.ExecutedRoutedEventArgs)
        AddPath(CType(e.Parameter, ObservableCollection(Of String)))
    End Sub

    Private Sub DeletePath_Executed(sender As System.Object, e As System.Windows.Input.ExecutedRoutedEventArgs)
        Dim lb = CType(e.Parameter, ListBox)
        While lb.SelectedItem IsNot Nothing
            CType(lb.ItemsSource, ObservableCollection(Of String)).Remove(lb.SelectedItem)
        End While
    End Sub

    Private Sub RefreshAddin_Executed(sender As System.Object, e As System.Windows.Input.ExecutedRoutedEventArgs)
        Dim lb = CType(e.Parameter, ListBox)
        If TypeOf lb.Tag Is InfoGen Then
            Me.Generator.Dispose()
            Me.Generator = New InfoGen(CType(lb.ItemsSource, IEnumerable(Of String)))
            Dim r = From addin In Settings.Settings.Default.InfoGens.CachedItem
                  Join aa In InfoG.GetSupportedPlayers On aa Equals addin.Name
                  Select addin Order By addin.Priority Ascending

            Dim r2 = From addinname In InfoG.GetSupportedPlayers
                     Let s = (From n In Settings.Settings.Default.InfoGens.CachedItem Select n.Name)
                     Where Not s.Contains(addinname)
                     Select New Settings.SettingsInfoGensItem() With {.Name = addinname, .IsEnabled = False, .Priority = Integer.MaxValue}

            Settings.Settings.Default.InfoGens.CachedItem = New ObservableCollection(Of Settings.SettingsInfoGensItem)(r.Concat(r2))

        ElseIf TypeOf lb.Tag Is InfoProccessors Then
            Me.Proccessor.Dispose()
            Me.Proccessor = New InfoProccessors(CType(lb.ItemsSource, IEnumerable(Of String)))
            Dim r = From addin In Settings.Settings.Default.Proccessors.CachedItem
                  Join aa In InfoP.ProccessorNames On aa Equals addin.Name
                  Select addin Order By addin.Priority Ascending

            Dim r2 = From addinname In InfoP.ProccessorNames
                     Let s = (From n In Settings.Settings.Default.Proccessors.CachedItem Select n.Name)
                     Where Not s.Contains(addinname)
                     Select New Settings.SettingsProccessorsItem() With {.Name = addinname, .IsEnabled = False, .Priority = Integer.MaxValue}

            Settings.Settings.Default.Proccessors.CachedItem = New ObservableCollection(Of Settings.SettingsProccessorsItem)(r.Concat(r2))
        ElseIf TypeOf lb.Tag Is InfoSenders Then
            Me.Sender.Dispose()
            Me.Sender = New InfoSenders(CType(lb.ItemsSource, IEnumerable(Of String)))
            Dim r = From addin In Settings.Settings.Default.Senders.CachedItem
                  Join aa In InfoS.Names On aa Equals addin.Name
                  Select addin Order By addin.Priority Ascending

            Dim r2 = From addinname In InfoS.Names
                     Let s = (From n In Settings.Settings.Default.Senders.CachedItem Select n.Name)
                     Where Not s.Contains(addinname)
                     Select New Settings.SettingsSendersItem() With {.Name = addinname, .IsEnabled = False, .Priority = Integer.MaxValue}

            Settings.Settings.Default.Senders.CachedItem = New ObservableCollection(Of Settings.SettingsSendersItem)(r.Concat(r2))
        End If
    End Sub

    Private Sub Check_Exectued(sender As System.Object, e As System.Windows.Input.ExecutedRoutedEventArgs)
        Dim lb As ListBox = e.Parameter
        If lb.SelectedItem Is Nothing Then Return
        If lb.Tag Is InfoG Then
            Dim name = CType(lb.SelectedItem, Settings.SettingsInfoGensItem).Name
            MessageBox.Show(String.Format("{0}的工作状态：{1}", name, If(InfoG.GetAvailablePlayer().Contains(name), "可以使用", "暂不可用")), "状态报告")
        ElseIf lb.Tag Is InfoP Then
            Dim name = CType(lb.SelectedItem, Settings.SettingsProccessorsItem).Name
            MessageBox.Show(String.Format("{0}的工作状态：{1}", name, If(InfoP.GetAvailabilities()(name), "可以使用", "暂不可用")), "状态报告")
        ElseIf lb.Tag Is InfoS Then
            Dim name = CType(lb.SelectedItem, Settings.SettingsSendersItem).Name
            MessageBox.Show(String.Format("{0}的工作状态：{1}", name, If(InfoS.GetAvailabilities()(name), "可以使用", "暂不可用")), "状态报告")
        End If
    End Sub

    Private Sub ShowSetting_Exectued(sender As System.Object, e As System.Windows.Input.ExecutedRoutedEventArgs)
        Dim lb As ListBox = e.Parameter
        If lb Is Nothing OrElse lb.Tag Is Nothing Then Return
        If lb.Tag Is InfoS Then
            InfoS.ShowSetting(CType(lb.SelectedItem, Settings.SettingsSendersItem).Name)
        ElseIf lb.Tag Is InfoP Then
            InfoP.ShowSetting(CType(lb.SelectedItem, Settings.SettingsProccessorsItem).Name)
        End If
    End Sub

    Private Sub StartWork_Exectued(sender As System.Object, e As System.Windows.Input.ExecutedRoutedEventArgs)
        My.Settings.IsWorking = Not My.Settings.IsWorking
    End Sub

    Private Sub ChangeHideState_Exectued(sender As System.Object, e As System.EventArgs)
        My.Settings.HideDefault = Not My.Settings.HideDefault
        If My.Settings.HideDefault Then
            Me.Hide()
        Else
            Me.Show()
        End If
    End Sub


    Protected Overloads Sub OnPropertyChanged(propertyName As String)
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
    End Sub
    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    Private Sub _sendTimer_Tick(sender As Object, e As System.EventArgs) Handles _sendTimer.Tick
        UpdateMessage()
    End Sub

    Private Sub UpdateMessage()
        System.Threading.ThreadPool.QueueUserWorkItem(Sub()
                                                          Dim collection =
                                                          (From c In
                                                           InfoG.GetAllInfomation((From g
                                                                                  In Settings.Settings.Default.InfoGens.CachedItem.AsParallel
                                                                                  Let ap As List(Of String) = InfoG.GetAvailablePlayer()
                                                                                  Where g.IsEnabled = True AndAlso ap.Contains(g.Name)
                                                                                  Order By g.Priority Ascending
                                                                                  Select g.Name).ToList())
                                                           Select c.Value)
                                                          If collection.Count = 0 OrElse collection.All(Function(d) d.Count = 0) Then Return
                                                          Dim result = (From dic In collection
                                                                        Where dic.Count <> 0
                                                                        From kvp In dic
                                                                        Select kvp).Distinct(
                                                                            New EqualityMaker(
                                                                                Of KeyValuePair(Of String, String))(
                                                                                Function(a, b) a.Key = b.Key)).ToDictionary(Function(kvp) kvp.Key, Function(kvp) kvp.Value)
                                                          InfoP.EnableProccessors =
                                                              Settings.Settings.Default.Proccessors.CachedItem.ToDictionary(
                                                                  Function(k) k.Name,
                                                                  Function(v) Tuple.Create(v.IsEnabled, CInt(v.Priority)))
                                                          Dim strToSend = InfoP.ProccessInfo(result)
                                                          InfoS.SendersState = Settings.Settings.Default.Senders.CachedItem.ToDictionary(
                                                              Function(k) k.Name, Function(v) Tuple.Create(v.IsEnabled, CInt(v.Priority)))
                                                          InfoS.Update(strToSend)
                                                      End Sub)
    End Sub

    <Flags()>
    Enum ControlKey As Integer
        None = &H0
        Alt = &H1
        Ctrl = &H2
        Shift = &H4
        Win = &H8
    End Enum

    Private Sub BindHotKey()
        If BindedHotKey Then
            UnbindHotKey()
        End If
        Dim modifier = If(My.Settings.KeyAlt, ControlKey.Alt, 0) Or
                       If(My.Settings.KeyControl, ControlKey.Ctrl, 0) Or
                       If(My.Settings.KeyShift, ControlKey.Shift, 0) Or
                       If(My.Settings.KeyWin, ControlKey.Win, 0)
        MyHotKeyID = (Now.Ticks Mod (&HFFFF - &HC000)) + &HC000
        Dim k As System.Windows.Forms.Keys
        If Not [Enum].TryParse(My.Settings.KeyMain, k) Then
            k = System.Windows.Forms.Keys.F2
        End If
        BindedHotKey = RegisterHotKey(wnd, MyHotKeyID, modifier, k)

    End Sub

    Private Sub UnbindHotKey()
        If BindedHotKey Then
            BindedHotKey = Not UnregisterHotKey(wnd, MyHotKeyID)
        End If
    End Sub

    <DebuggerStepThrough()>
    Private Function WndProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef Handled As Boolean) As IntPtr
        If msg = &H312 AndAlso wParam = MyHotKeyID Then
            Debug.WriteLine("Catch Hot Key!")
            UpdateMessage()
            Handled = True
        End If
    End Function


    Public Sub New()

        ' 此调用是设计器所必需的。
        InitializeComponent()

        ' 在 InitializeComponent() 调用之后添加任何初始化。
        NfyIcon = New forms.NotifyIcon()
        With NfyIcon
            .Icon = New draw.Icon("PLAY.ico")
            .Text = "My Now Playing"
            .Visible = True
            AddHandler .MouseDoubleClick, New forms.MouseEventHandler(AddressOf ChangeHideState_Exectued)
        End With
    End Sub
End Class
